﻿using System;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;

namespace Autodesk.AutoCAD.Windows.Features.PointCloud.PointCloudColorMapping
{

    public partial class PointCloudColorMappingDlg : System.Windows.Window
    {
        private IntPtr? target;
#if !EXTERNAL
        private Autodesk.AutoCAD.Internal.Forms.HelpProvider m_helpProvider;
#endif
        public static void LaunchPointCloudColorMappingDlg(IntPtr p)
        {
            PointCloudColorMappingDlg dlg = new PointCloudColorMappingDlg();
            dlg.target = p;
#if !EXTERNAL
            AutoCAD.ApplicationServices.Application.ShowModalWindow(dlg);
#endif
        }

        static PointCloudColorMappingDlg()
        {
            if (true)
            {
                //             var o = typeof(Validation).GetField("HasErrorPropertyKey", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null);
                //             Validation.HasErrorProperty .OverrideMetadata(typeof(TextBox),
                //                 new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.None, new PropertyChangedCallback(OnTextChanged)),(DependencyPropertyKey)o);
                //TODO: Shouldn't be using RegisterClassHandler for dialog specific events
                //      Consider using VisualTreeHelper to enumerate all controls in this dialog for event handler registration
                EventManager.RegisterClassHandler(typeof(TextBox), TextBox.PreviewLostKeyboardFocusEvent, new RoutedEventHandler(OnLostFocus));
                EventManager.RegisterClassHandler(typeof(TextBox), TextBox.PreviewMouseRightButtonDownEvent, new RoutedEventHandler(CheckClick));
                EventManager.RegisterClassHandler(typeof(TextBox), TextBox.ContextMenuOpeningEvent, new RoutedEventHandler(CheckContext));
                EventManager.RegisterClassHandler(typeof(ColorRamp), ColorRamp.ContextMenuOpeningEvent, new RoutedEventHandler(CheckContextRamp));
                EventManager.RegisterClassHandler(typeof(TextBox), TextBox.TextChangedEvent, (RoutedEventHandler)PointCloudColorMappingDlg.TextInputHandler);
                EventManager.RegisterClassHandler(typeof(ButtonBase), ButtonBase.ClickEvent, new RoutedEventHandler(CheckClick));
                EventManager.RegisterClassHandler(typeof(ButtonBase), ButtonBase.PreviewMouseLeftButtonDownEvent, new RoutedEventHandler(CheckClick));
                EventManager.RegisterClassHandler(typeof(ComboBox), ComboBox.PreviewMouseLeftButtonDownEvent, new RoutedEventHandler(CheckClick));
                EventManager.RegisterClassHandler(typeof(ColorRamp), ColorRamp.PreviewMouseLeftButtonDownEvent, new RoutedEventHandler(CheckClick));
                ToolTipService.ShowDurationProperty.OverrideMetadata(typeof(DependencyObject), new FrameworkPropertyMetadata(Int32.MaxValue));
            }
        }
        private static void TextInputHandler(object sender, RoutedEventArgs e)
        {
            if (_instance == null) return;
            dynamic pc = _instance.DataContext;
            pc.Dirty = true;
        }
        private static void OnLostFocus(object sender, RoutedEventArgs e)
        {
            if (_instance == null) return;
            var te = sender as TextBox;
            Validation.SetErrorTemplate(te, null);
            if (te != null)
            {
                var bind = BindingOperations.GetBindingExpressionBase(te, TextBox.TextProperty);
                if (bind != null)
                {
                    bind.UpdateSource();
                    if (bind.HasError || bind.Status == BindingStatus.UpdateSourceError)
                    {
                        bind.UpdateTarget();
                        Validation.MarkInvalid(bind, new ValidationError(new DataErrorValidationRule(), bind));
                        te.SelectAll();
                        e.Handled = true;
                    }
                }
            }
        }
        private static void CheckClick(object sender, RoutedEventArgs e)
        {
            if (_instance == null) return;
            var but = sender as UIElement;
            if (but != null)
            {
                var button = but as Button;
                if (button != null)
                {
                    if (button.IsCancel || "Help".Equals(button.Tag))
                        return;
                }
                but.Focus();
                var input = Keyboard.FocusedElement as UIElement;
                if (input != null && Validation.GetHasError(input))
                {
                    e.Handled = true;
                }
            }
        }

        private static void CheckContext(object sender, RoutedEventArgs e)
        {
            if (_instance == null) return;
            var input = Keyboard.FocusedElement as UIElement;
            if (sender != input)
            {
                e.Handled = true;
            }
        }

        private static void CheckContextRamp(object sender, RoutedEventArgs e)
        {
            if (_instance == null) return;
            (sender as UIElement).Focus();
            var input = Keyboard.FocusedElement as UIElement;
            if (sender != input)
            {
                e.Handled = true;
            }
        }

        protected internal static PointCloudColorMappingDlg _instance = null;

        public PointCloudColorMappingDlg()
        {
            _instance = this;
            InitializeComponent();
            this.Loaded += delegate { Reload(); };
            this.Closed += delegate { _instance = null; };
            this.SourceInitialized += delegate
            {
//                 Autodesk.AutoCAD.Win32.HideMinimizeAndMaximizeButtons(this);
            };
#if !EXTERNAL
            m_helpProvider = new Autodesk.AutoCAD.Internal.Forms.HelpProvider();
            m_helpProvider.HelpTopic = /*MSG0*/"POINTCLOUDCOLORMAP";
#endif
        }
        ~PointCloudColorMappingDlg()
        {
        }
        private void UpdateIntensityRamp(object sender, RoutedEventArgs e)
        {
            int nCols = R1.RangeList.Count;
            R1.NumColors = 2;
            R1.NumColors = nCols;
        }

        private void UpdateElevationRamp(object sender, RoutedEventArgs e)
        {
            int nCols = R2.RangeList.Count;
            R2.NumColors = 2;
            R2.NumColors = nCols;
        }

        private void ReverseRamp(object sender, RoutedEventArgs e)
        {
            var but = sender as FrameworkElement;
            var ramp = but.DataContext as Ramp;
            ramp.Reverse();
            
        }

        private void Reload()
        {
            this.DataContext = PointCloudMap.Load(target);
        }

        private void AplBtn_Click(object sender, RoutedEventArgs e)
        {
            this.SaveDB();
            Reload();
            dynamic data = this.DataContext ;
            data.Dirty = false;
        }

        private void CancelBtn_Click(object sender, RoutedEventArgs e)
        {
            this.Close();
        }

        private void OkBtn_Click(object sender, RoutedEventArgs e)
        {
            this.Close();
            this.SaveDB();
        }

        private void HlpBtn_Click(object sender, RoutedEventArgs e)
        {
#if !EXTERNAL
            m_helpProvider.InvokeHelp();
#endif
        }

        private void Root_KeyDown(object sender, KeyEventArgs e)
        {
#if !EXTERNAL
            if (e.Key == Key.F1)
                m_helpProvider.InvokeHelp();
#endif
            }

        private void SaveDB()
        {
            var data = this.DataContext as PointCloudMap;
            if (data.getProp<System.Collections.IList>("L1").Count == 0 || data.getProp<System.Collections.IList>("L2").Count == 0)
            {
                MessageBox.Show(this, Autodesk.AutoCAD.Windows.Features.PointCloudColorMapping.PointCloudColorMapping.DeleteColorSchemes, this.Title, MessageBoxButton.OK, MessageBoxImage.Information, MessageBoxResult.OK);
            }
            PointCloudMap.Save(data);

        }
        private void Select_Color(object sender, RoutedEventArgs e)
        {
            var spec = ((ClassificationRamp.Spec)((Button)sender).DataContext);
            Color? c = ColorSelector.SelectColor(spec.getProp<Color>("Color"));
            if (c != null)
            {
                spec.setProp("Color", c.GetValueOrDefault());
            }
        }

        private void CreateBtn_Click(object sender, RoutedEventArgs e)
        {
            bool? result = true;
            PointCloudMap pointCloudMap = DataContext as PointCloudMap;
            DependencyObject curColorScheme = ((sender as Button).DataContext) as DependencyObject;
            string name = null;
#if !EXTERNAL
            ColorSchemeNameDlg dlg = new ColorSchemeNameDlg(pointCloudMap, ColorSchemeNameDlg.DialogType.Create, null);
            result = AutoCAD.ApplicationServices.Application.ShowModalWindow(dlg);
            name = dlg.NewName;
#endif
            if (result == true)
            {
                pointCloudMap.AddScheme(curColorScheme, name, ((sender as Button).Tag) as string);
            }
        }

        private void DeleteBtn_Click(object sender, RoutedEventArgs e)
        {
            var o = (sender as FrameworkElement).DataContext as DependencyObject;
            if (o == null) return;

            var result = MessageBox.Show(this, String.Format(Autodesk.AutoCAD.Windows.Features.PointCloudColorMapping.PointCloudColorMapping.DeleteColorScheme, o.getProp<string>("Name")), this.Title, MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No);

            if (result == MessageBoxResult.Yes)
            {
                var d = this.DataContext as PointCloudMap;
                d.DeleteRamp(o);
            }
        }

        private void RenameBtn_Click(object sender, RoutedEventArgs e)
        {
#if !EXTERNAL
            PointCloudMap pointCloudMap = DataContext as PointCloudMap;
            DependencyObject curColorScheme = ((sender as Button).DataContext) as DependencyObject;
            string curName = curColorScheme.getProp<string>("Name");
            ColorSchemeNameDlg dlg = new ColorSchemeNameDlg(pointCloudMap, ColorSchemeNameDlg.DialogType.Rename, curName);
            bool? result = AutoCAD.ApplicationServices.Application.ShowModalWindow(dlg);
            if (result == true)
            {
                curColorScheme.setProp("Name", dlg.NewName);
            }
#endif
        }

        private void ClassificationSelection(object sender, SelectionChangedEventArgs e)
        {
            var grid = sender as DataGrid;
            if (grid == null) return;
            PointCloudMap.Selected.Clear();
            foreach (var item in grid.SelectedItems)
            {
                PointCloudMap.Selected.Add(item as ClassificationRamp.Spec);
            }
        }

        private void GridFocusChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            var grid = sender as DataGrid;
            if (grid == null) return;
            if (grid.IsKeyboardFocusWithin)
            {
                ClassificationSelection(grid, null);
            }
            else
            {
                PointCloudMap.Selected.Clear();
            }
        }

        private void Rectangle_Mouse(object sender, MouseButtonEventArgs e)
        {
            var rec = sender as FrameworkElement;
            (rec.Tag as ColorRamp).SelectColor(0);
        }
        private void Rectangle_Mouse1(object sender, MouseButtonEventArgs e)
        {
            var rec = sender as FrameworkElement;
            (rec.Tag as ColorRamp).SelectColor(0);
        }
        private void Rectangle_Mouse2(object sender, MouseButtonEventArgs e)
        {
            var rec = sender as FrameworkElement;
            (rec.Tag as ColorRamp).ChangeColorLast();
        }

    }
    class NullConverter : IValueConverter
    {

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (targetType == typeof(Visibility))
            {
                if (value == null)
                {
                    return Visibility.Collapsed;
                }
                else if (value is bool)
                {
                    return (bool)value ? Visibility.Visible : Visibility.Collapsed;
                }
                else
                    return Visibility.Visible;
            }
            if (value == null)
                return false;
            else if (value is bool)
                return value;
            else
                return true;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
    class Negater : IValueConverter
    {

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value == null || ! (value is  bool))
                return false;
            else
                return !(bool)value;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return !(bool)value;
        }
    }
    class UnitConverter : ValidationRule, IValueConverter, IMultiValueConverter
    {

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value == null) return null;
            return UnitUtils.DoubleToString((double)value);
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value == null) return null;
            try
            {
                return UnitUtils.StringToDouble((string)value);
            }
            catch (System.Exception ex)
            {
                return new ValidationResult(false,ex);

            }
        }

        object IMultiValueConverter.Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {   
            try
            {
	            return UnitUtils.DoubleToString(((double)values[1] - (double)values[0])/ (int)values[2]);
            }
            catch (System.Exception)
            {
                return String.Empty;
            }
        }

        object[] IMultiValueConverter.ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            dynamic data = PointCloudColorMappingDlg._instance.DataContext;
            dynamic scheme = data.DefaultScheme2;
            dynamic pc = data.PC;
            if (scheme != null&& pc != null)
            {
                var v = UnitUtils.StringToDouble((string)value);
                return new object[] { pc.MinEle, pc.MinEle + v * scheme.Num, scheme.Num };
            }
            return null;
        }

        public override ValidationResult Validate(object value, CultureInfo cultureInfo)
        {
            try
            {
                var v = UnitUtils.StringToDouble((string)value);
                if (v > 0 && !Double.IsInfinity(v))
                {
                    dynamic data = PointCloudColorMappingDlg._instance.DataContext;
                    dynamic scheme = data.DefaultScheme2;
                    dynamic pc = data.PC;
                    if (scheme != null && pc != null && Double.IsInfinity(pc.MinEle + v * scheme.Num))
                        return new ValidationResult(false, null);
                    return new ValidationResult(true, null);
                }
                else
                    return new ValidationResult(false, null);
            }
            catch (System.Exception ex)
            {
                return new ValidationResult(false, ex);

            }
        }
    }
    class MC : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            var t = values[0] as System.Collections.Generic.IEnumerable<object>;
            if (t == null) return null;
            if ((bool)values[1])
            {
                CollectionViewSource.GetDefaultView(t).Filter = o => ((DependencyObject)o).getProp<int>("Index") < 13;
                return t;
            }
            else
            {
                CollectionViewSource.GetDefaultView(t).Filter = null;
                return t;
            }
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

